#include "utilities.h"

void *timerSetThread(void* ptr)
{
	allTimers tempTimer;
	uoidStr uoidTemp;
	tempTimer.keepAliveTime = 0;
	struct timeval t1,t2;
	double time1, time2;
	map<int,allTimers>::iterator itMyTimers;
	multimap<int, int>::iterator itStatusResp;
	multimap<int, int>::iterator it1;
	multimap<int, int>::iterator it2;
	map<int,writeListData>::iterator it;
	set<int>::iterator itSet;
	list<uoidStr>::iterator itUOIDList;
	while(!dieChild)
	{
		gettimeofday(&t1,NULL);
		time1 = (double)(t1.tv_sec * 1000 + (double)t1.tv_usec/1000);
		usleep(100);
		gettimeofday(&t2,NULL);
		time2 = (double)(t2.tv_sec * 1000 + (double)t2.tv_usec/1000);
		pthread_mutex_lock(&timerlock);
		for(itMyTimers=myTimers.begin(); itMyTimers!=myTimers.end(); itMyTimers++)
		{
			tempTimer = myTimers[(*itMyTimers).first];
			tempTimer.keepAliveTime = tempTimer.keepAliveTime + time2 - time1;
			myTimers[(*itMyTimers).first] = tempTimer;
			if(tempTimer.keepAliveTime >= initMap["KeepAliveTimeout"].asDouble*1000)
			{
				if(printFlag==1)
				{
					printf("Time out occurred from port number %d",(*itMyTimers).first);
				}
				pthread_mutex_lock(&maplock);
				close(myMap.find((*itMyTimers).first)->second.socknumber);
				pthread_mutex_unlock(&maplock);
				pthread_exit(NULL);
			}
		}
		pthread_mutex_unlock(&timerlock);
		pthread_mutex_lock(&uoidlock);
		for(itUOIDList=myUOIDList.begin(); itUOIDList!=myUOIDList.end(); itUOIDList++)
		{
			uoidTemp = *itUOIDList;
			time1 = uoidTemp.timeOfTheDay;
			gettimeofday(&t2,NULL);
			time2 = (double)(t2.tv_sec * 1000 + (double)t2.tv_usec/1000);
			if(uoidTemp.msgLifeTime<((time2-time1)/1000))
			{
				myUOIDList.erase(itUOIDList);
			}
		}
		pthread_mutex_unlock(&uoidlock);
		if(globalStatusTime != -1 && statusFile[0] != '\0')
		{
			gettimeofday(&t2,NULL);
			time2 = (double)(t2.tv_sec * 1000 + (double)t2.tv_usec/1000);
			if((time2 - globalStatusTime) > (((int)(initMap["MsgLifetime"].asDouble)+5)*1000))
			{
				globalStatusTime = -1;
				FILE *file;
				char path[256];
				memset(path, '\0', 256);
				strcpy(path, statusFile);
				file = fopen(path, "w");
				if(file == NULL)
				{
					if(printFlag==1)
					{
						cout<<"Problem in opening the file"<<endl;
					}
					exit(0);
				}
				char dataStatus[256];
				memset(dataStatus, '\0', 256);
				strcpy(dataStatus, "V -t * -v 1.0a5\n");
				fputs(dataStatus, file);
				memset(dataStatus, '\0', 256);
				sprintf(dataStatus, "n -t * -s %d -c red -i black\n", port_recieve);
				fputs(dataStatus, file);
				set<int> setNodes;
				pthread_mutex_lock(&statusRespLock);
				for(itStatusResp=statusResp.begin(); itStatusResp!=statusResp.end(); itStatusResp++)
				{
					setNodes.insert((*itStatusResp).first);
					setNodes.insert((*itStatusResp).second);
				}
				pthread_mutex_unlock(&statusRespLock);
				pthread_mutex_lock(&statusRespLock);
				for(itSet=setNodes.begin(); itSet!=setNodes.end(); itSet++)
				{
					if((int)port_recieve != *itSet)
					{
						memset(dataStatus, '\0', 256);
						sprintf(dataStatus, "n -t * -s %d -c red -i black\n", *itSet);
						fputs(dataStatus, file);
					}
				}
				pthread_mutex_unlock(&statusRespLock);
				multimap<int, int>::iterator it;
				multimap<int, int> statusRespClone;
				pthread_mutex_lock(&statusRespLock);
				for(it1=statusResp.begin(); it1!=statusResp.end(); it1++)
				{
					for(it2=it1; it2!=statusResp.end(); it2++)
					{
						if(((*it1).first == (*it2).second) && ((*it1).second == (*it2).first))
						{
							statusResp.erase(it2);
						}						
					}
				}
				pthread_mutex_unlock(&statusRespLock);
				pthread_mutex_lock(&statusRespLock);
				for(itStatusResp=statusResp.begin(); itStatusResp!=statusResp.end(); itStatusResp++)
				{
						memset(dataStatus, '\0', 256);
						sprintf(dataStatus, "l -t * -s %d -d %d -c blue\n", (*itStatusResp).first, (*itStatusResp).second);
						fputs(dataStatus, file);
				}
				statusResp.clear();
				pthread_mutex_unlock(&statusRespLock);
				fclose(file);
			}
		}
		if(checkResponseTime!=-1)
		{
			gettimeofday(&t2,NULL);
			time2 = (double)(t2.tv_sec * 1000 + (double)t2.tv_usec/1000);
			if(time2 - checkResponseTime >= 1000*(initMap["JoinTimeout"].asDouble))
			{
				if(printFlag==1)
				{
					printf("Check Timeout\n");
				}
				pthread_cancel(commandLine);
				checkFlag = true;
				checkResponseTime = -1;
				////////////////////////////////////////////////////////////
				uint8_t notifyType = 3;
				char obj[256];
				strcpy(obj, "NTFY");
				msg_header notify_req;
				createMsgHdrStr(&notify_req,0xF7,1,obj,node_instance_id,sizeof(uint8_t));
					
				listBuffStruct lbtemp;
				memset(lbtemp.listBuff, '\0', 27+sizeof(uint8_t));
				fillMsgHdrBuffer(notify_req, lbtemp.listBuff);
				memcpy(&(lbtemp.listBuff[27]), &notifyType, sizeof(uint8_t));
				lbtemp.datalength = 27 + sizeof(uint8_t);
				lbtemp.logtype = 1;
				//Put it on every write queue
				pthread_mutex_lock(&writeMapMutex);
				if(printFlag==1)
				{
					cout<<"Size - "<<writeMap.size()<<endl;
				}
				notifyFlag = true;
				for(it=writeMap.begin(); it!=writeMap.end(); it++)
				{
					lbtemp.portNumber = (*it).first;
					writeListData listDataStr = writeMap[(*it).first];
					listDataStr.response.push_back(lbtemp);
					writeMap[(*it).first] = listDataStr;
					pthread_mutex_lock(&notifyLock);
					notifyCount++;
					if(printFlag==1)
					{
						cout<<"Notify Count set - "<<notifyCount<<endl;
					}
					pthread_mutex_unlock(&notifyLock);
				}
				pthread_mutex_unlock(&writeMapMutex);
				pthread_mutex_lock(&notifyLock);
				if(printFlag==1)
				{
					cout<<notifyCount<<writeMap.size()<<notifyFlag<<" flags"<<endl;
				}
				if((notifyCount == 0 || writeMap.size() == 0) && notifyFlag)
				{
					if(printFlag==1)
					{
						cout<<"Ending"<<endl;
					}
					pthread_mutex_unlock(&notifyLock);
					serverShutdown = true;
					dieChild = true;
					//kill(0, SIGUSR1);
					if(printFlag==1)
					{
						cout<<statusFile<<endl;
					}
					close(globalAcceptSock);
					//pthread_cancel(acceptThread);
					pthread_exit(NULL);
				}
				else
				{
					pthread_mutex_unlock(&notifyLock);
				}
			}
			else
			{

			}	
		}	
	}
	pthread_exit(NULL);
}
